#include "mouse.h"

#include<ctype.h>
#include<conio.h>
#include<stdio.h>
#include<fstream.h>
#include<math.h>
#include<dos.h>
#include<graphics.h>
#include<string.h>

#define GEOM_TOLER 1.0e-08

#define FEQ(a,b) (fabs(a - (b)) <=  GEOM_TOLER)   /* ( a == b ) */
#define FLT(a,b) (    (a - (b)) <  -GEOM_TOLER)   /* ( a <  b ) */
#define FGT(a,b) (    (a - (b)) >   GEOM_TOLER)   /* ( a >  b ) */
#define FLE(a,b) (    (a - (b)) <=  GEOM_TOLER)   /* ( a <= b ) */
#define FGE(a,b) (    (a - (b)) >= -GEOM_TOLER)   /* ( a >= b ) */
#define FNE(a,b) (fabs(a - (b)) >   GEOM_TOLER)   /* ( a >= b ) */

#define FEQZ(a) (fabs(a) <=  GEOM_TOLER)   /* ( a == rzero ) */
#define FLTZ(a) (    (a) <  -GEOM_TOLER)   /* ( a <  rzero ) */
#define FGTZ(a) (    (a) >   GEOM_TOLER)   /* ( a >  rzero ) */
#define FLEZ(a) (    (a) <=  GEOM_TOLER)   /* ( a <= rzero ) */
#define FGEZ(a) (    (a) >= -GEOM_TOLER)   /* ( a >= rzero ) */
#define FNEZ(a) (fabs(a) >   GEOM_TOLER)   /* ( a >= rzero ) */

int get_key(void);
void dan_delay(double);

double global_min_speed, global_max_speed, global_acceleration;
double global_feed_speed, global_x_steps_per_unit = 1;
double global_y_steps_per_unit = 1, global_z_steps_per_unit = 1;
double global_x_backlash_steps = 0, global_y_backlash_steps = 0, global_z_backlash_steps = 0;
int global_use_feed_move_buffer = 0;
int global_interrupt_21 = 9;
int global_interrupt_A1 = 0;
int global_units = 0; //steps
double global_users_pi = 3.1415926535897932384626433832795;
double global_feed_factor = 1;
double global_arc_speed = 1.0;
int global_parallel_port = 0x3bc;

// define the maximum graph values, use about half this value in reality
// to give room for error
#define MAX_GRAPH_VALUES 100

extern int backlash_graphs_used(void);

class CGraph{
	private:
	int m_num;
	// values always in steps
	double m_wanted[MAX_GRAPH_VALUES];
	double m_needed[MAX_GRAPH_VALUES];

	public:
	CGraph(){m_num = 0;}
	void AddAValue(double wanted, double needed);
	double FindNeededValue(double wanted);
	double FindWantedValue(double needed);
};

void CGraph::AddAValue(double wanted, double needed){
	if(m_num >= MAX_GRAPH_VALUES)return;

	m_wanted[m_num] = wanted;
	m_needed[m_num] = needed;

	m_num++;
}

double CGraph::FindNeededValue(double wanted){
	if(wanted < m_wanted[0])return m_needed[0];
	if(wanted > m_wanted[m_num-1])return m_needed[m_num-1];

	int i;
	for(i = 0; i<m_num; i++){
		if(wanted<m_wanted[i+1]){
			double param = (wanted - m_wanted[i])/(m_wanted[i+1] - m_wanted[i]);
			double needed = m_needed[i] + param * (m_needed[i+1] - m_needed[i]);
			return needed;
		}
	}

	return m_needed[m_num-1];// shouldn't get here
}

double CGraph::FindWantedValue(double needed){
	if(needed < m_needed[0])return m_wanted[0];
	if(needed > m_needed[m_num-1])return m_wanted[m_num-1];

	int i;
	for(i = 0; i<m_num; i++){
		if(needed<m_needed[i+1]){
			double param = (needed - m_needed[i])/(m_needed[i+1] - m_needed[i]);
			double wanted = m_wanted[i] + param * (m_wanted[i+1] - m_wanted[i]);
			return wanted;
		}
	}

	return m_wanted[m_num-1];// shouldn't get here
}

CGraph x_plus_graph;
CGraph x_minus_graph;
CGraph y_plus_graph;
CGraph y_minus_graph;

#define NUM_TOOLS 20

class global_variables{
public:
	int output_step0;
	int output_step1;
	int output_step2;
	int output_value;
	int output_value_b;
	int output_value_c;
	int output_high;
	int xdir, ydir, zdir;
	double x_value, y_value, z_value, i_value, j_value; // measured in steps
	double feed_value;
	double dwell_value;
	double tools[NUM_TOOLS];
	int current_tool;
	double x_offset;
	double y_offset;

	global_variables(void);
}globals;

global_variables::global_variables(void){
	output_step0 = 0;
	output_step1 = 0;
	output_step2 = 0;
	output_value = 15;
	output_value_b = 15;
	output_value_c = 15;
	output_high = 3;
	x_value = 0; y_value = 0; z_value = 0;
	i_value = 0; j_value = 0;
	feed_value = 100;
	dwell_value = 1;
	xdir = 1;
	ydir = 1;
	zdir = 1;
	current_tool = 0;
	for(int i = 0; i<NUM_TOOLS;i++){
		tools[i] = 0;
	}
	x_offset = 0;
	y_offset = 0;
}

double GetXNeeded(double wanted){
	if(!global_units)return wanted;// steps mode
	if(!backlash_graphs_used())return wanted;// machine doesn't support these graphs
	if(globals.xdir > 0)return x_plus_graph.FindNeededValue(wanted);
	return x_minus_graph.FindNeededValue(wanted);
}

double GetXWanted(double needed){
	if(!global_units)return needed;// steps mode
	if(!backlash_graphs_used())return needed;// machine doesn't support these graphs
	if(globals.xdir > 0)return x_plus_graph.FindWantedValue(needed);
	return x_minus_graph.FindWantedValue(needed);
}

double GetYNeeded(double wanted){
	if(!global_units)return wanted;// steps mode
	if(!backlash_graphs_used())return wanted;// machine doesn't support these graphs
	if(globals.ydir > 0)return y_plus_graph.FindNeededValue(wanted);
	return y_minus_graph.FindNeededValue(wanted);
}

double GetYWanted(double needed){
	if(!global_units)return needed;// steps mode
	if(!backlash_graphs_used())return needed;// machine doesn't support these graphs
	if(globals.ydir > 0)return y_plus_graph.FindWantedValue(needed);
	return y_minus_graph.FindWantedValue(needed);
}
